package com.xiaoma.h5testdemo.common.utils


import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.util.Log
import android.view.View
import android.view.Window
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import java.lang.reflect.Field
import kotlin.math.abs


/**
 * author: liangjingbo
 * date: 2023/12/13
 * describe:
 */
object KeyboardUtils {

    private var sDecorViewDelta = 0

    fun fixAndroidBug5497(window: Window, context: Context) {
        val softInputMode = window.attributes.softInputMode
        window.setSoftInputMode(
            softInputMode and WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE.inv())
        val contentView = window.findViewById<FrameLayout>(android.R.id.content)
        val contentViewChild = contentView.getChildAt(0)
        val paddingBottom = contentViewChild.paddingBottom
        val contentViewInvisibleHeightPre5497 = intArrayOf(getContentViewInvisibleHeight(window, context))
        contentView.viewTreeObserver.addOnGlobalLayoutListener {
            val height: Int = getContentViewInvisibleHeight(window, context)
            if (contentViewInvisibleHeightPre5497[0] != height) {
                contentViewChild.setPadding(contentViewChild.paddingLeft,
                    contentViewChild.paddingTop, contentViewChild.paddingRight,
                    paddingBottom + getDecorViewInvisibleHeight(window,context))
                contentViewInvisibleHeightPre5497[0] = height
            }
        }
    }


    private fun getContentViewInvisibleHeight(window: Window, context: Context): Int {
        val contentView = window.findViewById<View>(android.R.id.content) ?: return 0
        val outRect = Rect()
        contentView.getWindowVisibleDisplayFrame(outRect)
        Log.d("KeyboardUtils",
            "getContentViewInvisibleHeight: " + (contentView.bottom - outRect.bottom))
        val delta = abs(contentView.bottom - outRect.bottom)
        return if (delta <= getStatusBarHeight(context) + getNavBarHeight(context)) {
            0
        } else delta
    }

    @SuppressLint("InternalInsetResource", "DiscouragedApi")
    private fun getStatusBarHeight(context: Context): Int {
        val res = context.resources
        val resourceId = res.getIdentifier("status_bar_height", "dimen", "android")
        return if (resourceId != 0) {
            res.getDimensionPixelSize(resourceId)
        } else {
            0
        }
    }

    @SuppressLint("InternalInsetResource", "DiscouragedApi")
    private fun getNavBarHeight(context: Context): Int {
        val res = context.resources
        val resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android")
        return if (resourceId != 0) {
            res.getDimensionPixelSize(resourceId)
        } else {
            0
        }
    }

    private fun getDecorViewInvisibleHeight(window: Window, context: Context): Int {
        val decorView = window.decorView
        val outRect = Rect()
        decorView.getWindowVisibleDisplayFrame(outRect)
        Log.d("KeyboardUtils",
            "getDecorViewInvisibleHeight: " + (decorView.bottom - outRect.bottom))
        val delta = abs(decorView.bottom - outRect.bottom)
        if (delta <= getNavBarHeight(context) + getStatusBarHeight(context)) {
            sDecorViewDelta = delta
            return 0
        }
        return delta - sDecorViewDelta
    }


    fun fixSoftInputLeaks(window: Window,context: Context) {
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
            ?: return
        val leakViews = arrayOf("mLastSrvView", "mCurRootView", "mServedView", "mNextServedView")
        for (leakView in leakViews) {
            try {
                val leakViewField: Field = InputMethodManager::class.java.getDeclaredField(leakView)
                if (!leakViewField.isAccessible) {
                    leakViewField.isAccessible = true
                }
                val obj: Any = leakViewField.get(imm) as? View ?: continue
                val view = obj as View
                if (view.rootView === window.decorView.rootView) {
                    leakViewField.set(imm, null)
                }
            } catch (ignore: Throwable) { /**/
            }
        }
    }
}